package com.jeejio.common.rcv.decoration

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.text.TextUtils
import android.view.View
import androidx.recyclerview.widget.RecyclerView

/**
 * Author: JFangZ
 * Email: janezhang1901@163.com
 * Date: 2021/4/19 11:37
 * Description:
 */
abstract class StickyDecoration constructor(builder: Builder) : RecyclerView.ItemDecoration() {
    private var height = 0
    private var backgroundColor: Int = 0x00000000
    private var textColor: Int = 0xFF000000.toInt()
    private var textSize = 36f
    private var textMarginLeft = 0
    private var spanCount = 1
    private val paint = Paint()
    private val textBounds = Rect()

    init {
        this.height = builder.height
        this.backgroundColor = builder.backgroundColor
        this.textColor = builder.textColor
        this.textSize = builder.textSize
        this.textMarginLeft = builder.textMarginLeft
        this.spanCount = builder.spanCount

        paint.isAntiAlias = true
        paint.textSize = textSize
    }

    /**
     * Description:在 Canvas 上绘制内容作为 RecyclerView 的 Item 的装饰，会在 Item 绘制之前绘制
     * 也就是说，如果该 Decoration 没有设置偏移的话，Item 的内容会覆盖该 Decoration。
     * Date:2018/9/14
     */
    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDraw(c, parent, state)
    }

    /**
     * Description:在 Canvas 上绘制内容作为 RecyclerView 的 Item 的装饰，会在 Item 绘制之后绘制
     * 也就是说，如果该 Decoration 没有设置偏移的话，该 Decoration 会覆盖 Item 的内容。
     * Date:2018/9/14
     */
    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(c, parent, state)
        var previousStickyHeaderName: String?
        var currentStickyHeaderName: String?
        val left = parent.left
        //Decoration 的右边位置
        val right = parent.right
        //获取 RecyclerView 的 Item 数量
        val childCount = parent.childCount
        for (i in 0 until childCount) {
            val childView = parent.getChildAt(i)
            //判断上一个 position 粘性头部的文字与当前 position 的粘性头部文字是否相同，如果相同则跳过绘制
            val position = parent.getChildAdapterPosition(childView)
            currentStickyHeaderName = getStickyHeaderName(position)
            if (TextUtils.isEmpty(currentStickyHeaderName)) {
                continue
            }
            if (position < spanCount || i < spanCount) {
                //Decoration 的底边位置
                var bottom = Math.max(childView.top, height)
                //当当前 Decoration 的 Bottom 比下一个 View 的 Decoration 的 Top （即下一个 View 的 getTop() - mHeight）大时
                //就应该使当前 Decoration 的 Bottom 等于下一个 Decoration 的 Top，形成推动效果
                val nextChildView = parent.getChildAt(i + spanCount)
                val nextStickyHeaderName = getStickyHeaderName(position + spanCount)
                if (nextChildView != null && !TextUtils.equals(currentStickyHeaderName, nextStickyHeaderName) && bottom > nextChildView.top - height) {
                    bottom = nextChildView.top - height
                }
                //Decoration 的顶边位置
                val top = bottom - height
                paint.color = backgroundColor
                c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), paint)
                //绘制文字
                paint.color = textColor
                paint.getTextBounds(currentStickyHeaderName, 0, currentStickyHeaderName!!.length, textBounds)
                c.drawText(currentStickyHeaderName, left.toFloat() + textMarginLeft.toFloat(), bottom.toFloat() - height.toFloat() / 2 + textBounds.height().toFloat() / 2, paint)
                continue
            }
            previousStickyHeaderName = getStickyHeaderName(position - spanCount)
            if (!TextUtils.equals(previousStickyHeaderName, currentStickyHeaderName)) {
                //Decoration 的底边位置
                var bottom = Math.max(childView.top, height)
                //当当前 Decoration 的 Bottom 比下一个 View 的 Decoration 的 Top （即下一个 View 的 getTop() - mHeight）大时
                //就应该使当前 Decoration 的 Bottom 等于下一个 Decoration 的 Top，形成推动效果
                val nextChildView = parent.getChildAt(i + spanCount)
                val nextStickyHeaderName = getStickyHeaderName(position + spanCount)
                if (nextChildView != null && !TextUtils.equals(currentStickyHeaderName, nextStickyHeaderName) && bottom > nextChildView.top - height) {
                    bottom = nextChildView.top - height
                }
                //Decoration 的顶边位置
                val top = bottom - height
                paint.color = backgroundColor
                c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), paint)
                //绘制文字
                paint.color = textColor
                paint.getTextBounds(currentStickyHeaderName, 0, currentStickyHeaderName!!.length, textBounds)
                c.drawText(currentStickyHeaderName, left.toFloat() + textMarginLeft.toFloat(), bottom.toFloat() - height.toFloat() / 2 + textBounds.height().toFloat() / 2, paint)
            }
        }
    }

    /**
     * Description:为 Decoration 设置偏移
     * Date:2018/9/14
     */
    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        super.getItemOffsets(outRect, view, parent, state)
        //outRect 相当于 Item 的整体绘制区域,设置 left、top、right、bottom 相当于设置左上右下的内间距
        //如设置 outRect.top = 5 则相当于设置 paddingTop 为 5px。
        val position = parent.getChildAdapterPosition(view)
        val stickyHeaderName = getStickyHeaderName(position)
        if (TextUtils.isEmpty(stickyHeaderName)) {
            return
        }
        if (position < spanCount) {
            outRect.top = height
            return
        }
        val previousStickyHeaderName = getStickyHeaderName(position - spanCount)
        if (!TextUtils.equals(stickyHeaderName, previousStickyHeaderName)) {
            outRect.top = height
        }
    }

    abstract fun getStickyHeaderName(position: Int): String?

    class Builder {
        internal var height = 100
        internal var backgroundColor: Int = 0x00000000
        internal var textColor: Int = 0xFF000000.toInt()
        internal var textSize: Float = 36f
        internal var textMarginLeft = 0
        internal var spanCount = 1
        fun setHeight(height: Int): Builder {
            this.height = height
            return this
        }

        fun setBackgroundColor(backgroundColor: Int): Builder {
            this.backgroundColor = backgroundColor
            return this
        }

        fun setTextColor(textColor: Int): Builder {
            this.textColor = textColor
            return this
        }

        fun setTextSize(textSize: Float): Builder {
            this.textSize = textSize
            return this
        }

        fun setTextMarginLeft(textMarginLeft: Int): Builder {
            this.textMarginLeft = textMarginLeft
            return this
        }

        fun setSpanCount(spanCount: Int): Builder {
            this.spanCount = spanCount
            return this
        }
    }
}